package com.winit.openapi.apiadapter.controller;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.fastjson.JSONObject;
import com.winit.common.spi.context.CommandContext;
import com.winit.erp.spi.bpartner.vo.Bpartner;
import com.winit.erp.spi.common.CurrencyRateService;
import com.winit.erp.spi.common.command.QueryCurrencyRateCommand;
import com.winit.erp.spi.finance.FinanceCustomerAccountService;
import com.winit.oms.spi.outbound.OutboundOrderService;
import com.winit.oms.spi.outbound.OutboundWinitProductService;
import com.winit.oms.spi.outbound.command.order.QueryUsableWinitProductCommand;
import com.winit.oms.spi.vo.v2.response.FeeDetailResult;
import com.winit.oms.spi.vo.v2.response.QueryUsableWinitProductResult;
import com.winit.openapi.apiadapter.controller.builder.OrderAdapteBuilder;
import com.winit.openapi.apiadapter.vo.Order3eFeeResultVo;
import com.winit.openapi.apiadapter.vo.OutBoundOrderFeeDetailVo;
import com.winit.openapi.apiadapter.vo.QueryOutboundOrderFeeResultVo;
import com.winit.openapi.constants.ApiConstant;
import com.winit.openapi.constants.ErrorCode;
import com.winit.openapi.exception.ApiException;
import com.winit.openapi.model.RequestMsg;
import com.winit.openapi.model.ResponseMsg;
import com.winit.openapi.util.BeanUtils;
import com.winit.openapi.util.ValidateUtil;
import com.winit.pms.spi.v2.instance.pscInstance.ProductInstanceService;
import com.winit.pms.spi.v2.instance.pscInstance.command.ProductInstanceByDeliveryModeCommand;
import com.winit.pms.spi.v2.instance.pscInstance.vo.ProductInstance;

/**
 * 出库单费用预估接口适配
 * 老接口地址：<url>http://developer.winit.com.cn/Index/index.php?s=Index/index
 * /id/14/l/zh-cn<url>
 * 
 * @version <pre>
 * Author   Version     Date        Changes
 * minghao.deng     1.0         2016年12月12日     Created
 *
 * </pre>
 * @since 1.
 */
@Controller
public class QueryOutboundOrderFeeAdapteController extends AbstractAdapteController {

    private Logger                        logger                     = LoggerFactory.getLogger(QueryOutboundOrderFeeAdapteController.class);

    private static final String           CURRENCY_USD               = "USD";

    /**
     * 订单处理费CODE
     */
    private static final String           CHARGE_CODE_ORDER_HANDING  = "102";

    /**
     * 最后一公里派送费用CODE
     */
    private static final String           CHARGE_CODE_ORDER_DELIVERY = "103";

    @Resource
    private OutboundOrderService          outboundOrderService;

    @Resource
    private OutboundWinitProductService   outboundWinitProductService;

    @Resource
    private ProductInstanceService        productInstanceService;

    @Resource
    private CurrencyRateService           currencyRateService;
    @Resource
    private FinanceCustomerAccountService financeCustomerAccountService;

    /**
     * 出库单预估费用
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/queryDeliveryFee")
    public String queryDeliveryFee(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {

        return doAdapte(requestMsg, responseMsg);
    }
    
    @Override
    protected void validateInputJson(RequestMsg requestMsg) {
        // 获取参数
        JSONObject json = JSONObject.parseObject(requestMsg.getData().toString());
        if (null == json) {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        //单号必填
        ValidateUtil.validMaxLength(json, "outboundOrderNum", 64, true);

        ValidateUtil.validMaxLength(json, "deliveryWayID", 20, false);
        
        ValidateUtil.validMaxLength(json, "insuranceTypeID", 20, false);
    }
    
    private List<QueryOutboundOrderFeeResultVo> buildResult(List<QueryUsableWinitProductResult> productList) {
        List<QueryOutboundOrderFeeResultVo> voList = new ArrayList<QueryOutboundOrderFeeResultVo>();
        Bpartner bpartner = CommandContext.getContext().get(ApiConstant.API_BPARTNER);
        BigDecimal balance = financeCustomerAccountService.getUsableBalance(bpartner.getcBpartnerId(), CURRENCY_USD);
        for (QueryUsableWinitProductResult productFeeVo : productList) {
            QueryOutboundOrderFeeResultVo vo = BeanUtils.copyProperties(productFeeVo,
                QueryOutboundOrderFeeResultVo.class);
            vo.setFeeDetail(BeanUtils.copyList(productFeeVo.getFeeDetail(), OutBoundOrderFeeDetailVo.class));
            vo.setTotalAmountToUSD(convertFee(vo.getTotalAmount(), vo.getCurrency(), CURRENCY_USD));
            vo.setAvailableBalance(balance);
            int compareResult = balance.compareTo(vo.getTotalAmountToUSD());
            vo.setIsAccountLocked(1 == compareResult ? "N" : "Y");
            for (OutBoundOrderFeeDetailVo detailVo : vo.getFeeDetail()) {
                OrderAdapteBuilder.convertChargeUnit(detailVo.getChargeUnit());
                detailVo.setAmountToUSD(convertFee(detailVo.getAmount(), detailVo.getCurrency(), CURRENCY_USD));
            }
            voList.add(vo);

        }

        return voList;
    }

    private BigDecimal convertFee(BigDecimal oriFee, String fromCurrency, String toCurrency) {

        if (null == oriFee) {
            return BigDecimal.ZERO;
        }
        BigDecimal rate = convertRate(fromCurrency, toCurrency);

        return rate.multiply(oriFee);
    }

    /**
     * 获取汇率
     * 
     * @return
     */
    private BigDecimal convertRate(String fromCurrency, String toCurrency) {
        // 如果原始货币是美金，就不需要货币转换
        if (fromCurrency.equalsIgnoreCase(toCurrency)) {
            return BigDecimal.ONE;
        }
        QueryCurrencyRateCommand command = new QueryCurrencyRateCommand();
        command.setCtx(CommandContext.getContext());
        command.setFromCurrencyCode(fromCurrency);
        command.setToCurrencyCode(toCurrency);
        command.setConvDate(new Date());

        return currencyRateService.getCurrencyRateByFromCurCodeTOEndCurCode(command);
    }

    @Override
    protected boolean checkCustomerTansferConfig(RequestMsg requestMsg, ResponseMsg responseMsg) {
//        JSONObject json = JSONObject.parseObject(requestMsg.getData().toString());
//
//        String orderNo = json.getString("outboundOrderNum");

        return true;
    }

    @Override
    protected void doAdapteInOpenAPI(RequestMsg requestMsg, ResponseMsg responseMsg) {
        JSONObject json = JSONObject.parseObject(requestMsg.getData().toString());
        String orderNo = json.getString("outboundOrderNum");
        QueryUsableWinitProductCommand command = new QueryUsableWinitProductCommand();
        command.setOrderNo(orderNo);
        List<QueryUsableWinitProductResult> list = new ArrayList<QueryUsableWinitProductResult>();
        // 2.调用新费用查询接口，查询出所有产品费用
        List<QueryUsableWinitProductResult> productList = outboundWinitProductService.getUsableWinitProduct(command);
        if (CollectionUtils.isEmpty(productList)) {
            throw new ApiException(ErrorCode.ORDER_NOT_FIND_EXPRESS_PRODUCT);
        }
        // 如果传入了deliveryWayID则根据派送方式匹配产品，计算费用。否则给出所有推荐产品的费用
        if (json.containsKey("deliveryWayID")) {
            // 1.根据传入的派送方式查询出产品
            ProductInstanceByDeliveryModeCommand deliveryCommand = new ProductInstanceByDeliveryModeCommand();
            String deliveryWayId = json.getString("deliveryWayID");
            deliveryCommand.setDeliveryMode(deliveryWayId);
            ProductInstance product = productInstanceService.getProductByDeliveryMode(deliveryCommand);
            if (null == product) {
                logger.info("通过派送方式ID查询产品失败，派送方式ID：" + deliveryWayId);
                throw new ApiException(ErrorCode.ORDER_NOT_FIND_EXPRESS_PRODUCT);
            }
            for (QueryUsableWinitProductResult usableProduct : productList) {
                if (ErrorCode.SUCCESS.equals(usableProduct.getErrorCode())
                    && product.getCode().equalsIgnoreCase(usableProduct.getWinitProductCode())) {
                    list.add(usableProduct);
                }
            }
            if (CollectionUtils.isEmpty(list)) {
                throw new ApiException(ErrorCode.FEE_ITEM_NOT_FOUND_ERROR);
            }
        } else {
            list.addAll(productList);
        }

        // 费用接口分别返回老的和新的接口
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("feeList", buildResult(list));
        data.put("summany", buildOldFeeReturnString(list));
        responseMsg.setData(data);

    }

    private String buildOldFeeReturnString(List<QueryUsableWinitProductResult> productList) {
        if (CollectionUtils.isEmpty(productList)) {
            return null;
        }
        QueryUsableWinitProductResult product = productList.get(0);
        Bpartner bpartner = CommandContext.getContext().get(ApiConstant.API_BPARTNER);
        BigDecimal balance = financeCustomerAccountService.getUsableBalance(bpartner.getcBpartnerId(), CURRENCY_USD);
        Order3eFeeResultVo feeVo = new Order3eFeeResultVo();
        feeVo.setAccountAvailableBalance(balance);
        feeVo.setOrderTotalFee(product.getTotalAmount() == null ? BigDecimal.ZERO : product.getTotalAmount());
        feeVo.setTargetCurrency(CURRENCY_USD);
        feeVo.setOriginalCurrency(product.getCurrency());
        feeVo.setOrderTotalFeeToUSD(convertFee(feeVo.getOrderTotalFee(), feeVo.getOriginalCurrency(), CURRENCY_USD));
        feeVo.setOrderInsuranceFee(BigDecimal.ZERO);
        feeVo.setOrderInsuranceFeeToUSD(BigDecimal.ZERO);
        int compareResult = balance.compareTo(feeVo.getOrderTotalFeeToUSD());
        feeVo.setTrayQty(product.getTrayQty() == null ? 0 : product.getTrayQty().intValue());
        feeVo.setIsAccountLocked(1 == compareResult ? "N" : "Y");

        feeVo.setOrderDeliveryFee(BigDecimal.ZERO);
        feeVo.setOrderDeliveryFeeToUSD(BigDecimal.ZERO);
        feeVo.setOrderHandlingFee(BigDecimal.ZERO);
        feeVo.setOrderHandlingFeeToUSD(BigDecimal.ZERO);
        for (FeeDetailResult feeDetail : product.getFeeDetail()) {
            if (CHARGE_CODE_ORDER_DELIVERY.equals(feeDetail.getChargeCode())) {
                feeVo.setOrderDeliveryFee(feeDetail.getAmount() == null ? BigDecimal.ZERO : feeDetail.getAmount());
                feeVo.setOrderDeliveryFeeToUSD(convertFee(feeDetail.getAmount(), feeDetail.getCurrency(), CURRENCY_USD));
                // 计费类型以订单派送费用为准-老单
                feeVo.setChargeType(OrderAdapteBuilder.convertChargeUnit(feeDetail.getChargeUnit()));
            } else if (CHARGE_CODE_ORDER_HANDING.equals(feeDetail.getChargeCode())) {
                feeVo.setOrderHandlingFee(feeDetail.getAmount() == null ? BigDecimal.ZERO : feeDetail.getAmount());
                feeVo.setOrderHandlingFeeToUSD(convertFee(feeDetail.getAmount(), feeDetail.getCurrency(), CURRENCY_USD));

            }

        }

        return feeVo.toString();
    }
}
